package cheme.ProcessEditor.Policies;

import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.FeedbackHelper;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;

import cheme.ProcessEditor.Figures.Util.ChemePolylineDecoration;
import cheme.ProcessModel.IParent;
import cheme.ProcessModel.Cmds.CreateStreamCmd;
import cheme.ProcessModel.Cmds.CreateTerminalStreamCmd;
import cheme.ProcessModel.Cmds.ReconnectStreamCmd;
import cheme.ProcessModel.ProcessUnits.TerminalSink;
import cheme.ProcessModel.ProcessUnits.TerminalSource;
import cheme.ProcessModel.ProcessUnits.Streams.AbstractStream;


/**
 * This node edit policy can create a source or sink node automatically when the
 * host is clicked. It provides a generic gray box for source location feedback 
 * along with the typical line feedback provided b the base class 
 * {@link GraphicalNodeEditPolicy}.
 * 
 * @author Jonathan
 *
 */
public class ImplicitTerminalNodePolicy extends GraphicalNodeEditPolicy
{
	/**
	 * The source/sink feedback diplayed during creates.
	 */
	protected IFigure sourceSinkFeedback;

	class Box extends Figure
	{
		Box(Point centerPoint)
		{
			Rectangle bounds = new Rectangle(centerPoint.x - 10, centerPoint.y - 10, 20, 20);
			super.setBounds(bounds);

			setBackgroundColor(ColorConstants.black);
			setBorder(new LineBorder(ColorConstants.white));
			setOpaque(true);
		}
	}

	@Override
	protected Command getConnectionCompleteCommand(CreateConnectionRequest request)
	{
		CreateTerminalStreamCmd newCmd = null;
		if(request.getStartCommand() instanceof CreateTerminalStreamCmd)
		{
			newCmd = new CreateTerminalStreamCmd((CreateTerminalStreamCmd)request.getStartCommand());
		}
		else if(request.getStartCommand() instanceof CreateStreamCmd)
		{
			newCmd = new CreateTerminalStreamCmd((CreateStreamCmd)request.getStartCommand());
		}
		
		Point pRelative = new Point(request.getLocation());
		getHostFigure().translateToRelative(pRelative);

		IParent parent = (IParent)getHost().getModel();
		
		newCmd.setSink(new TerminalSink(parent, pRelative), parent);
			
		return newCmd;
	}
	
	@Override
	protected Command getConnectionCreateCommand(CreateConnectionRequest request)
	{
		CreateTerminalStreamCmd cmd = null;
			Point pRelative = new Point(request.getLocation());
			getHostFigure().translateToRelative(pRelative);
			
			IParent parent = (IParent)getHost().getModel();
			
			TerminalSource source = new TerminalSource(parent, pRelative);
			cmd = new CreateTerminalStreamCmd(source);
			
			request.setStartCommand(cmd);
		
		return cmd;
	}

	@Override
	protected Command getReconnectTargetCommand(ReconnectRequest request)
	{
		ReconnectStreamCmd cmd = new ReconnectStreamCmd();

		IParent parent = (IParent)getHost().getModel();
		
		cmd.setParent(parent);
		cmd.setStream((AbstractStream)request.getConnectionEditPart().getModel());
		
		Point pRelative = new Point(request.getLocation());
		getHostFigure().translateToRelative(pRelative);
		
		cmd.setNewSink(new TerminalSink(parent, pRelative));
		
		return cmd;
	}

	@Override
	protected Command getReconnectSourceCommand(ReconnectRequest request)
	{
		/*
		 * So this guy would want to create a new Sink to accomodate an 
		 * non-PU drop. After that, it ought to be similar to the 
		 * initial creation methods above. 
		 */
		
		ReconnectStreamCmd cmd = new ReconnectStreamCmd();

		IParent parent = (IParent)getHost().getModel();
		
		cmd.setParent(parent);
		cmd.setStream((AbstractStream)request.getConnectionEditPart().getModel());
		
		Point pRelative = new Point(request.getLocation());
		getHostFigure().translateToRelative(pRelative);
		
		cmd.setNewSource(new TerminalSource(parent, pRelative));
		
		return cmd;
	}
	
	protected IFigure createDummyFigure(CreateConnectionRequest request)
	{
		Point pRelative = new Point(request.getLocation());
		getHostFigure().translateToRelative(pRelative);
		return new Box(pRelative);
	}
	
	protected Connection createDummyConnection(Request req)
	{
		PolylineConnection connection = new PolylineConnection();
		
		ChemePolylineDecoration decorator = new ChemePolylineDecoration();
		decorator.setScale(12, 6);
		connection.setTargetDecoration(decorator);
		
		return connection;
	}
	
	/**
	 * Returns the FeedbackHelper that is ready to use. The feedback helper must
	 * be configured with the connection that will be used to display feedback,
	 * and that connection must be added to the appropriate layer in the
	 * diagram.
	 * 
	 * JB 6-4-2007: I agumented the base class method to include a small 
	 * rectangular figure to represent the to-be-created terminal PU. Could
	 * have left the dummy feedback line naked and jsut used an XY locator to
	 * pin the origin point to the initial mouse click location.
	 * 
	 * But the dummy figure is more visible.
	 * 
	 * @param request the CreateConnectionRequest
	 * @return a FeedbackHelper
	 */
	@Override
	protected FeedbackHelper getFeedbackHelper(CreateConnectionRequest request)
	{
		if(feedbackHelper == null)
		{
			feedbackHelper = new FeedbackHelper();

			Point pRelative = new Point(request.getLocation());
			getHostFigure().translateToRelative(pRelative);
			
			Point pAbsolute = new Point(request.getLocation());
//			getHostFigure().translateToRelative(pRelative);

			sourceSinkFeedback = createDummyFigure(request);
			addFeedback(sourceSinkFeedback);

			connectionFeedback = createDummyConnection(request);
			
			connectionFeedback.setConnectionRouter(getDummyConnectionRouter(request));
			connectionFeedback.setSourceAnchor(new ChopboxAnchor(sourceSinkFeedback));
			feedbackHelper.setConnection(connectionFeedback);
			addFeedback(connectionFeedback);

			feedbackHelper.update(null, pAbsolute);
		}
		return feedbackHelper;
	}
	
	/**
	 * @see org.eclipse.gef.EditPolicy#deactivate()
	 */
	@Override
	public void deactivate()
	{
		if(connectionFeedback != null)
		{
			removeFeedback(sourceSinkFeedback);
			removeFeedback(connectionFeedback);
			
			feedbackHelper = null;
			sourceSinkFeedback = null;
			connectionFeedback = null;
		}
		super.deactivate();
	}

	/**
	 * Erases connection feedback if necessary. Frees unused fields.
	 * 
	 * @param request the CreateConnectionRequest
	 */
	@Override
	protected void eraseCreationFeedback(CreateConnectionRequest request)
	{
		if(connectionFeedback != null)
		{
			removeFeedback(sourceSinkFeedback);
			removeFeedback(connectionFeedback);
			
			feedbackHelper = null;
			sourceSinkFeedback = null;
			connectionFeedback = null;
		}
	}
}
